//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem
// FILE:            XortElementImpl.cpp - runtime support of XortElement object
// AUTHOR:          Vladimir Gumenuk
// DATE:            26-Jun-2014
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xobject.h"
#include "xruntime.h"
#include "xcode.h"
#include "XortElementImpl.h"

CXortElementImpl::CXortElementImpl( XRuntime *pRT ) : XObject( pRT )
{

}

CXortElementImpl::~CXortElementImpl()
{

}

/* The current API of the XortElement:
    1 byte bType;
    2 byte bAccess;
    3 char    _s1;
    4 byte    _u1;
    5 short   _s2;
    6 word    _u2;
    7 int     _s4;
    8 dword   _u4;
    9 qlong   _s8;
    10 qword   _u8;
    11 float   _r4;
    12 real    _r8;
    13 IXObject _p;
    
    1 void Clear();
*/

int CXortElementImpl::Invoke( dword dwFuncIndex, XRuntime *pRuntime )
{
    int iRet = XORT_OK;

    XCELLSARRAY& stack = pRuntime->get_Stack();
    const XortElement& sysFrame = stack.top();
    if( sysFrame.bAccess != sys_Frame )
        return ERR_INVALID_STACK_SYSFRAME;

    dword dwStackBase = pRuntime->get_StackBase();
    dword dwArgsCount = sysFrame.bType;
    
    InstructionData retPrim; retPrim.m_bInstrCode = p_ret; retPrim.m_bTypeAddr = t_v; // prepare ret primitive
    
    switch( dwFuncIndex )
    {
    case 1: // void Clear();
        if( dwArgsCount != 0 ) // arguments ??
            return ERR_INVALID_ARG_COUNT;
        m_Element.Clear(); // invoke function
        break;

    case 2: // void SetValue( XortElement vVal );
        {
            if( dwArgsCount != 1 ) 
                return ERR_INVALID_ARG_COUNT;

            XortElement& argValue = stack.get( dwStackBase - dwArgsCount );
            if( argValue.bType != t_p ) return ERR_INVALID_TYPE;
            if( !argValue._p ) { // do nothing, just clear element

                m_Element.Clear();
            }
            else
            {
                if( argValue._p->GetType() != t_xelement )
                    return ERR_INVALID_TYPE;

                CXortElementImpl *pElem = (CXortElementImpl *)argValue._p;
                m_Element.SetValue( pElem->m_Element );
            }
        }
        break;

    default:
        return ERR_METHOD_NOT_FOUND;
    }
    

    iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack

    return iRet;
}

int CXortElementImpl::Put( dword dwVarIndex, const XortElement& Value )
{
    switch( dwVarIndex )
    {
    case 1 : if( Value.bType != t_u1 ) return ERR_TYPES_MISMATCH; m_Element.bType   = Value._u1; break; // byte bType;
    case 2 : if( Value.bType != t_u1 ) return ERR_TYPES_MISMATCH; m_Element.bAccess = Value._u1; break; // byte bAccess;
    case 3 : if( Value.bType != t_s1 ) return ERR_TYPES_MISMATCH; m_Element._s1     = Value._s1; break; // char    _s1;
    case 4 : if( Value.bType != t_u1 ) return ERR_TYPES_MISMATCH; m_Element._u1     = Value._u1; break; // byte    _u1;
    case 5 : if( Value.bType != t_s2 ) return ERR_TYPES_MISMATCH; m_Element._s2     = Value._s2; break; // short   _s2;
    case 6 : if( Value.bType != t_u2 ) return ERR_TYPES_MISMATCH; m_Element._u2     = Value._u2; break; // word    _u2;
    case 7 : if( Value.bType != t_s4 ) return ERR_TYPES_MISMATCH; m_Element._s4     = Value._s4; break; // int     _s4;
    case 8 : if( Value.bType != t_u4 ) return ERR_TYPES_MISMATCH; m_Element._u4     = Value._u4; break; // dword   _u4;
    case 9 : if( Value.bType != t_s8 ) return ERR_TYPES_MISMATCH; m_Element._s8     = Value._s8; break; // qlong   _s8;
    case 10: if( Value.bType != t_u8 ) return ERR_TYPES_MISMATCH; m_Element._u8     = Value._u8; break; // qword   _u8;
    case 11: if( Value.bType != t_r4 ) return ERR_TYPES_MISMATCH; m_Element._r4     = Value._r4; break; // float   _r4;
    case 12: if( Value.bType != t_r8 ) return ERR_TYPES_MISMATCH; m_Element._r8     = Value._r8; break; // real    _r8;
    case 13: if( Value.bType != t_p )  return ERR_TYPES_MISMATCH; 
        if( m_Element._p ) {
            m_Element._p->Release();
            m_Element._p = NULL;
        }
        m_Element._p  = Value._p; // IXObject _p;
        if( m_Element._p )
            m_Element._p->AddRef();
        break;
    default:
        return ERR_INVALID_PROPERTY_INDEX;
    }

    return XORT_OK;
}

int CXortElementImpl::Get( dword dwVarIndex, XortElement& Value )
{
    Value.Clear();

    switch( dwVarIndex )
    {
    case 1 : Value.bType = t_u1; Value._u1 = m_Element.bType; break; // byte bType;
    case 2 : Value.bType = t_u1; Value._u1 = m_Element.bAccess; break; // byte bAccess;
    case 3 : Value.bType = t_s1; Value._s1 = m_Element._s1; break; // char    _s1;
    case 4 : Value.bType = t_u1; Value._u1 = m_Element._u1; break; // byte    _u1;
    case 5 : Value.bType = t_s2; Value._s2 = m_Element._s2; break; // short   _s2;
    case 6 : Value.bType = t_u2; Value._u2 = m_Element._u2; break; // word    _u2;
    case 7 : Value.bType = t_s4; Value._s4 = m_Element._s4; break; // int     _s4;
    case 8 : Value.bType = t_u4; Value._u4 = m_Element._u4; break; // dword   _u4;
    case 9 : Value.bType = t_s8; Value._s8 = m_Element._s8; break; // qlong   _s8;
    case 10: Value.bType = t_u8; Value._u8 = m_Element._u8; break; // qword   _u8;
    case 11: Value.bType = t_r4; Value._r4 = m_Element._r4; break; // float   _r4;
    case 12: Value.bType = t_r8; Value._r8 = m_Element._r8; break; // real    _r8;
    case 13: Value.bType = t_p ;
        if( Value._p ) {
            Value._p->Release();
            Value._p = NULL;
        }
        Value._p  = m_Element._p; // IXObject _p;
        if( Value._p )
            Value._p->AddRef();
        break;
    default:
        return ERR_INVALID_PROPERTY_INDEX;
    }

    Value.bAccess = usr_VarRW;

    return XORT_OK;
}

void CXortElementImpl::SetElement( XortElement& e )
{
    m_Element = e;
}

string CXortElementImpl::FormatToString()
{
    return xFormatElementValue( m_Element, 16 );
}